/**
 * @brief 串口驱动
 * @author 张勇 41204@qq.com
 * @date 2022-04
*/

#include <string.h>
#include <stm32f4xx_ll_bus.h>
#include <stm32f4xx_ll_gpio.h>
#include <stm32f4xx_ll_usart.h>

#include "share/cccompat.h"
#include "share/console.h"
//#include "share/ymodem.h"
#include "unios.h"

#include "mcu.h"
#include "_mcu_gpio.h"
#include "_mcu_uart.h"

// 串口时钟使能并复位(波特率等参数只有复位之后才能重新设置)
static std_err_t _uart_reset(USART_TypeDef* port) {
    switch((uintptr_t)port) {
        case (uintptr_t)USART1: { LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_USART1); LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_USART1); break; }
        case (uintptr_t)USART2: { LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_USART2); LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_USART2); break; }
        case (uintptr_t)USART3: { LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_USART3); LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_USART3); break; }
        case (uintptr_t)UART4 : { LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_UART4 ); LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_UART4 ); break; }
        case (uintptr_t)UART5 : { LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_UART5 ); LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_UART5 ); break; }
        case (uintptr_t)USART6: { LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_USART6); LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_USART6); break; }
        #ifdef UART7
        case (uintptr_t)UART7 : { LL_APB2_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_UART7 ); LL_APB2_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_UART7 ); break; }
        #endif
        #ifdef UART8
        case (uintptr_t)UART8 : { LL_APB2_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_UART8 ); LL_APB2_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_UART8 ); break; }
        #endif
        default: return STD_ERR_INVALID_ARG;
    }
    return STD_ERR_OK;
}

IRQn_Type mcu_uart_irqn(mcu_uart_t *dev) {
    switch((uintptr_t)dev->port) {
        case (uintptr_t)USART1: return USART1_IRQn;
        case (uintptr_t)USART2: return USART2_IRQn;
        case (uintptr_t)USART3: return USART3_IRQn;
        case (uintptr_t)UART4 : return UART4_IRQn ;
        case (uintptr_t)UART5 : return UART5_IRQn ;
        case (uintptr_t)USART6: return USART6_IRQn;
        #ifdef UART7
        case (uintptr_t)UART7 : return UART7_IRQn ;
        #endif
        #ifdef UART8
        case (uintptr_t)UART8 : return UART8_IRQn ;
        #endif
        default: return USART1_IRQn;
    }
}

// 初始化 UART 使用的 GPIO 引脚
static std_err_t _uart_init_gpio(USART_TypeDef* port, mcu_gpio_mux_func_init_t txpin_mux_init, mcu_gpio_mux_func_init_t rxpin_mux_init) {
    mcu_gpio_num_t tx    = txpin_mux_init();
    GPIO_TypeDef *txport = mcu_gpio_port(tx);
    uint32_t txpin       = mcu_gpio_pin(tx);
    LL_GPIO_SetPinMode      (txport, txpin, LL_GPIO_MODE_ALTERNATE);
    LL_GPIO_SetPinSpeed     (txport, txpin, LL_GPIO_SPEED_FREQ_HIGH);
    LL_GPIO_SetPinOutputType(txport, txpin, LL_GPIO_OUTPUT_PUSHPULL);
    LL_GPIO_SetPinPull      (txport, txpin, LL_GPIO_PULL_UP);

    mcu_gpio_num_t rx    = rxpin_mux_init();
    GPIO_TypeDef *rxport = mcu_gpio_port(rx);
    uint32_t rxpin       = mcu_gpio_pin(rx);
    LL_GPIO_SetPinMode      (rxport, rxpin, LL_GPIO_MODE_ALTERNATE);
    LL_GPIO_SetPinSpeed     (rxport, rxpin, LL_GPIO_SPEED_FREQ_HIGH);
    LL_GPIO_SetPinOutputType(rxport, rxpin, LL_GPIO_OUTPUT_PUSHPULL);
    LL_GPIO_SetPinPull      (rxport, rxpin, LL_GPIO_PULL_UP);

    return STD_ERR_OK;
}

std_err_t mcu_uart_init(
    mcu_uart_t *dev,
    mcu_gpio_mux_func_init_t txpin_mux_init,
    mcu_gpio_mux_func_init_t rxpin_mux_init,
    uint32_t baudrate,
    mcu_uart_databits_t databits,
    mcu_uart_stopbits_t stopbits,
    mcu_uart_parity_t parity) 
{
    if(!dev || !dev->port) { return STD_ERR_INVALID_ARG; }
    std_err_t err;

    // 初始化 UART 使用的 GPIO 引脚
    err = _uart_init_gpio(dev->port, txpin_mux_init, rxpin_mux_init); if(err) return err;

    // 串口复位(波特率等参数只有复位之后才能重新设置)
    err = _uart_reset(dev->port); if(err) return err;

    // 配置USART参数
    LL_USART_InitTypeDef init = {0};
    init.BaudRate = baudrate;
    init.TransferDirection = LL_USART_DIRECTION_TX_RX;
    init.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
    init.OverSampling = LL_USART_OVERSAMPLING_16;
    switch(databits) {
        case MCU_UART_DATABITS_8: init.DataWidth = LL_USART_DATAWIDTH_8B; break;
        case MCU_UART_DATABITS_9: init.DataWidth = LL_USART_DATAWIDTH_9B; break;
        default: return STD_ERR_NOT_SUPPORTED;
    }
    switch(stopbits) {
        case MCU_UART_STOPBITS_0_5: init.StopBits = LL_USART_STOPBITS_0_5; break;
        case MCU_UART_STOPBITS_1  : init.StopBits = LL_USART_STOPBITS_1  ; break;
        case MCU_UART_STOPBITS_1_5: init.StopBits = LL_USART_STOPBITS_1_5; break;
        case MCU_UART_STOPBITS_2  : init.StopBits = LL_USART_STOPBITS_2  ; break;
        default: return STD_ERR_NOT_SUPPORTED;
    }
    switch(parity) {
        case MCU_UART_PARITY_NO:   init.Parity = LL_USART_PARITY_NONE; break;
        case MCU_UART_PARITY_EVEN: init.Parity = LL_USART_PARITY_EVEN; break;
        case MCU_UART_PARITY_ODD:  init.Parity = LL_USART_PARITY_ODD ; break;
        default: return STD_ERR_NOT_SUPPORTED;
    }
    if(SUCCESS != LL_USART_Init(dev->port, &init)) return STD_ERR_FAIL;
    LL_USART_ConfigAsyncMode(dev->port);

    // 启用 USART
    LL_USART_Enable(dev->port);
    return STD_ERR_OK;
}

std_err_t mcu_uart_set_rxbyte_callback(mcu_uart_t* dev, func_uart_rxbyte_t rxbyte_callback, void *rxbyte_cookie) {
    if(!dev || !rxbyte_callback) return STD_ERR_INVALID_ARG;
    dev->rxhandler = rxbyte_callback; dev->rxcookie = rxbyte_cookie;
    return STD_ERR_OK;
}

/// @brief 设置 UART 回调函数: 发送缓冲区空
std_err_t mcu_uart_set_txempty_callback(mcu_uart_t* dev, func_uart_txempty_t txempty_callback, void *txempty_cookie) {
    if(!dev || !txempty_callback) return STD_ERR_INVALID_ARG;
    dev->txhandler = txempty_callback; dev->txcookie = txempty_cookie;
    return STD_ERR_OK;
}

/*
USART_FLAG_xxx/USART_IT_xxx:
   CTS:  CTS Change flag (not available for UART4 and UART5)
   LBD:  LIN Break detection flag
   TXE:  Transmit data register empty flag
   TC:   Transmission Complete flag
   RXNE: Receive data register not empty flag
   IDLE: Idle Line detection flag
   ORE:  OverRun Error flag
   NE:   Noise Error flag
   FE:   Framing Error flag
   PE:   Parity Error flag

 - IDLE, ORE, NE, FE, PE 中断清除方法：
   USART_GetITStatus()
   USART_ReceiveData()
*/

/// @brief 统一中断处理入口
_RAMCODE_ void mcu_uart_irq_handler(mcu_uart_t* dev) {
    if(!dev || !dev->port) return;
    USART_TypeDef* uart = dev->port;

    // 判断是否有接收中断
    __IO uint32_t SR = uart->SR;
    uint8_t ch = (uart->DR & 0xFF);

    if( (SR & USART_FLAG_PE) || (SR & USART_FLAG_FE) || (SR & USART_FLAG_NE) ) {
        // 数据错误，丢弃
        LL_USART_ClearFlag_PE(uart);
        LL_USART_ClearFlag_FE(uart);
        LL_USART_ClearFlag_NE(uart);
        return;
    }

    if( (SR & USART_FLAG_ORE) || (SR & USART_FLAG_IDLE) ) {
        // 数据有效，继续
        LL_USART_ClearFlag_ORE(uart);
        LL_USART_ClearFlag_IDLE(uart);
    }

    if(SR & USART_IT_RXNE) {
        if(dev->rxhandler) {
            // 回调字符接收函数
            dev->rxhandler(dev, dev->rxcookie, ch);
        } else if(dev->trx && dev->trx->on_rx_data) {
            // 调用 TRX 的回调函数
            dev->trx->on_rx_data(dev->trx->on_rx_data_cookie, dev->trx, NULL, 0, 0, &ch, 1);
        }
    }

    // 判断是否有发送中断
    if((SR & USART_FLAG_TC) || (SR & USART_FLAG_TXE)) {
        if(dev->txhandler) {
            // 调用发送完成中断回调
            dev->txhandler(dev, dev->txcookie);
        } else if(dev->trx && dev->trx->on_tx_empty) {
            // 调用 TRX 的回调函数
            dev->trx->on_tx_empty(dev->trx->on_tx_empty_cookie, dev->trx, NULL, NULL);
        } else {
            // 如果没人管，则必须将 TXE 中断关闭，否则会不断地产生中断，导致系统 down 机
            mcu_uart_tx_irq_enable(dev, false);
        }
    }
}

std_err_t mcu_uart_rx_irq_enable(mcu_uart_t* dev, bool sw) {
    if(!dev || !dev->port) { return STD_ERR_INVALID_ARG; }

    if(sw) {
        LL_USART_EnableIT_RXNE(dev->port);
        mcu_intc_enable(mcu_intc(), mcu_uart_irqn(dev), true);
    } else {
        //mcu_intc_enable(mcu_intc(), mcu_uart_irqn(dev), false);
        LL_USART_DisableIT_RXNE(dev->port);
    }

    return STD_ERR_OK;
}

std_err_t mcu_uart_tx_irq_enable(mcu_uart_t* dev, bool sw) {
    if(!dev || !dev->port) { return STD_ERR_INVALID_ARG; }

    if(sw) {
        LL_USART_EnableIT_TC(dev->port);
        LL_USART_EnableIT_TXE(dev->port);
        mcu_intc_enable(mcu_intc(), mcu_uart_irqn(dev), true);
    } else {
        //mcu_intc_enable(mcu_intc(), mcu_uart_irqn(dev), false);
        LL_USART_DisableIT_TC(dev->port);
        LL_USART_DisableIT_TXE(dev->port);
    }

    return STD_ERR_OK;
}

std_err_t mcu_uart_clear_rxfifo(mcu_uart_t* dev) {
	// STM32F4 USART 没有 FIFO
    return STD_ERR_OK;
}

std_err_t mcu_uart_clear_txfifo(mcu_uart_t* dev) {
	// STM32F4 USART 没有 FIFO
    return STD_ERR_OK;
}

std_err_t mcu_uart_putc(mcu_uart_t* dev, uint8_t ch) {
    if(!dev || !dev->port) { return STD_ERR_INVALID_ARG; }
    // 等待发送缓冲区为空
    while(!LL_USART_IsActiveFlag_TXE(dev->port));
    // 发送数据
    LL_USART_TransmitData8(dev->port, ch);
    return STD_ERR_OK;
}

std_err_t mcu_uart_getc(mcu_uart_t* dev, uint8_t *ch) {
    if(!dev || !dev->port || !ch) { return STD_ERR_INVALID_ARG; }
    // 如果接收缓冲区中没有数据就立即返回错误，不等待
    //while(!LL_USART_IsActiveFlag_RXNE(dev->port));
    if(!LL_USART_IsActiveFlag_RXNE(dev->port)) return STD_ERR_BUFFER_UNDERFLOW;
    // 读取数据
    *ch = LL_USART_ReceiveData8(dev->port);
    return STD_ERR_OK;
}

std_err_t mcu_uart_send(mcu_uart_t* dev, const void* data, size_t len, size_t *sentlen) {
    if(!dev || !dev->port || !data || !len) { return STD_ERR_INVALID_ARG; }
    const uint8_t* bytes = (const uint8_t*)data;
    if(sentlen) *sentlen = 0;

    for(size_t i = 0; i<len; i++) {
        while(!LL_USART_IsActiveFlag_TXE(dev->port));
        LL_USART_TransmitData8(dev->port, bytes[i]);
    }

    // 确保最后一个字节真正传输完成了，再返回
    // 否则，对于485驱动来说，返回后会关闭芯片的发送使能，从而导致最后一个字节发送不完！！！
    while(!LL_USART_IsActiveFlag_TC(dev->port));
    if(sentlen) *sentlen = len;
    return STD_ERR_OK;
}

std_err_t mcu_uart_sendstr(mcu_uart_t* dev, const char* str) {
    return mcu_uart_send(dev, str, strlen(str), NULL);
}

rx_ret_t mcu_uart_receive(mcu_uart_t* dev, void* buf, size_t bufsize, size_t *rxlen, long timeout, /*long lead,*/ long interval, const char *okFlag, rx_flag_t okFlagType, const char *failFlag, rx_flag_t failFlagType) {
    if(!dev || !dev->port || !buf || !bufsize) { return RX_RET_ERROR; }

    // 清空缓冲区，以免因残留数据导致数据标志匹配错误
    memset(buf, 0, bufsize);
    // 留一个位置给尾部 '\0'
    bufsize--;

    // 同步接收数据时，应关闭接收中断，防止数据被中断服务程序读走了
    mcu_uart_rx_irq_enable(dev, false);

    uint32_t start = unios_ms_now();
    uint32_t lastByteTime = 0;
    size_t len = 0;
    char *data = (char*)buf;
    rx_ret_t ret;

    while(1) {
        if(LL_USART_IsActiveFlag_RXNE(dev->port)) {
            // 收到数据
            data[len++] = LL_USART_ReceiveData8(dev->port);
            lastByteTime = unios_ms_now();

            // 因缓冲区满中止
            if(len >= bufsize) { ret = RX_RET_FULL; break; }
            // 因 OK 标志中止
            if(okFlag && okFlagType == RX_FLAG_STRING && strstr(data, okFlag)) { ret = RX_RET_OK; break; }
            // 因 Fail 标志中止
            if(failFlag && failFlagType == RX_FLAG_STRING && strstr(data, failFlag)) { ret = RX_RET_FAIL; break; }
        }

        // 因总超时中止
        if(timeout > 0 && (unios_ms_elapsed(start) >= timeout)) { ret = RX_RET_TIMEOUT; break; }
        // 因间隔超时中止
        if(interval > 0 && lastByteTime && (unios_ms_elapsed(lastByteTime) >= interval)) { ret = RX_RET_INTERVAL; break; }
    }

    if(rxlen) *rxlen = len;
    return ret;
}

/// 用于标准 I/O 的 UART 端口
static mcu_uart_t *_stduart = NULL;

void mcu_stduart_set(mcu_uart_t* dev) {
	_stduart = dev;
}

mcu_uart_t* mcu_stduart_get() {
	return _stduart;
}
